자동 대응 시스템

자동 대응 시스템 (Spring Boot Webhook)

Alertmanager가 보낸 경보를 수신하여 화이트리스트/쿨다운 정책으로 Docker 재시작 등의 자동 대응 액션을 실행하는 Spring Boot 앱.


구성 개요

Alertmanager → POST /alert (webhook) → Spring Boot App
                                              ↓
                                    토큰 검증 → 쿨다운 확인
                                              ↓
                                    화이트리스트 매칭
                                              ↓
                                    docker / ssh / script 실행
                                    (dryRun 모드 시 로그만)

의존성 (build.gradle.kts)

dependencies {
  implementation("org.springframework.boot:spring-boot-starter-web")
  implementation("org.springframework.boot:spring-boot-starter-validation")
  implementation("org.springframework.boot:spring-boot-starter-actuator")
  implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
  // SSH 액션 필요 시
  implementation("com.hierynomus:sshj:0.37.0")
}

application.yml

server:
  port: 8080

alert:
  token: "SHARED_SECRET"          # 단순 토큰 검증
  dryRun: true                    # true 시 실행 안 하고 로그만
  cooldownSeconds: 120            # 같은 액션 반복 방지
  allowedActions:                 # 화이트리스트
    - "docker:restart"
    - "docker:scale"
    - "script:/opt/actions/restart.sh"

docker:
  host: "unix:///var/run/docker.sock"  # 권장: 제한된 래퍼 사용

Alert DTO

public record AlertPayload(
  String status,
  List<Alert> alerts
) {
  public record Alert(
    Map<String,String> labels,
    Map<String,String> annotations
  ) {}
}

Controller (토큰 검증 + 쿨다운 + dryRun)

@RestController
@RequestMapping("/alert")
public class AlertWebhookController {
  private final ActionService action;
  private final AtomicLong lastActionTs = new AtomicLong(0);
  @Value("${alert.token}") String token;
  @Value("${alert.dryRun:true}") boolean dryRun;
  @Value("${alert.cooldownSeconds:120}") long cooldown;

  @PostMapping
  public ResponseEntity<?> handle(
      @RequestHeader(value="X-Alert-Token", required=false) String hdrToken,
      @RequestBody AlertPayload payload) {

    if (token != null && !token.equals(hdrToken))
      return ResponseEntity.status(401).body("invalid token");

    long now = System.currentTimeMillis();
    if (now - lastActionTs.get() < cooldown * 1000)
      return ResponseEntity.ok("cooldown");

    boolean matched = payload.alerts().stream().anyMatch(a ->
      "ApiDown".equals(a.labels().get("alertname")) &&
      "critical".equals(a.labels().get("severity"))
    );

    if (matched) {
      String cmd = "docker:restart leafy_api";
      if (dryRun) action.audit("DRYRUN", cmd, payload);
      else { action.run(cmd); lastActionTs.set(now); }
    }
    return ResponseEntity.ok("ok");
  }
}

Alertmanager 연동 설정

# alertmanager.yml
receivers:
  - name: "webhook-handler"
    webhook_configs:
      - url: "http://spring-app:8080/alert"
        send_resolved: true

보안 주의사항


관련 개념